Skip to content

child_process: add subprocess.timedOut - #66639

Open
marcopiraccini wants to merge 3 commits into
nodejs:mainfrom
marcopiraccini:child-process-timed-out
Open

marcopiraccini wants to merge 3 commits into
nodejs:mainfrom
marcopiraccini:child-process-timed-out

Conversation

@marcopiraccini

@marcopiraccini marcopiraccini commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

When a child process receives its kill signal because timeout expired, callers cannot distinguish that from a signal sent for another reason.

Add subprocess.timedOut for spawn(), exec(), execFile() and fork(), and error.timedOut on errors returned by exec() and execFile(). The flag becomes true only when the timeout successfully sends the signal; it does not guarantee that the process has terminated.

This revisits #51608, which proposed the same property for #51561 but closed without landing. That review requested documentation and noted failing CI. This PR includes API documentation and regression tests for timeout expiry, normal exit, manual termination, non-timeout errors, and descendants keeping stdio open after the child exits.

Fixes: #51561
Refs: #51608

When the timeout option of spawn(), exec(), execFile() or fork()
expires, the child is sent the kill signal and exits with that signal.
Nothing told the caller that the timeout was the reason.

Set subprocess.timedOut to true when the kill signal is sent because of
the timeout, and add the same flag to the error passed to the exec()
and execFile() callback.

Fixes: nodejs#51561
Refs: nodejs#51608
Signed-off-by: marcopiraccini <marco.piraccini@gmail.com>
@nodejs-github-bot nodejs-github-bot added child_process Issues and PRs related to the child_process subsystem. needs-ci PRs that need a full CI run. labels Oct 10, 2026
@marcopiraccini
marcopiraccini marked this pull request as ready for review October 10, 2026 09:25
@codecov

codecov Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.47%. Comparing base (ae5a0f4) to head (6acb1e8).
⚠️ Report is 46 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #66639      +/-   ##
==========================================
- Coverage   92.78%   90.47%   -2.31%     
==========================================
  Files         422      791     +369     
  Lines      193692   277097   +83405     
  Branches    29881    53279   +23398     
==========================================
+ Hits       179718   250709   +70991     
- Misses      13645    16813    +3168     
- Partials      329     9575    +9246     
Files with missing lines Coverage Δ
lib/child_process.js 91.44% <100.00%> (+0.04%) ⬆️
lib/internal/child_process.js 95.13% <100.00%> (+1.68%) ⬆️

... and 511 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@inoway46 inoway46 added semver-minor PRs that contain new features and should be released in the next minor version. request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. labels Oct 11, 2026
@inoway46

Copy link
Copy Markdown
Contributor

Adding semver-minor since this introduces the public subprocess.timedOut and error.timedOut properties.

@github-actions github-actions Bot removed the request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. label Oct 11, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@inoway46 inoway46 added the resume-ci Add this label to resume the latest eligible Jenkins CI run on a PR with an approving review. label Oct 12, 2026
@github-actions github-actions Bot added resume-ci-failed Resuming CI with the resume-ci label failed and requires manual intervention. and removed resume-ci Add this label to resume the latest eligible Jenkins CI run on a PR with an approving review. labels Oct 12, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Failed to resume CI

   ✖  test/parallel/test-child-process-spawn-timeout-kill-signal.js
   ℹ  https://ci.nodejs.org/job/node-test-commit-osx/nodes=macos15-x64/74044/consoleText
✖  Refusing to resume CI: failures reference files changed by this PR
Full Auto Start CI output
�[36m⠋�[39m Validating Jenkins credentials
�[36m⠋�[39m Validating Jenkins credentials
✔  Jenkins credentials valid
�[36m⠙�[39m Looking for CI runs for pull request 66639
�[36m⠙�[39m Looking for CI runs for pull request 66639
�[36m⠙�[39m Getting PR from nodejs/node/pull/66639
�[36m⠙�[39m Getting reviews from nodejs/node/pull/66639
�[36m⠙�[39m Getting comments from nodejs/node/pull/66639
✔  Found PR CI job 78312
�[36m⠹�[39m Querying data for job/node-test-pull-request/78312/
�[36m⠹�[39m Querying data for job/node-test-pull-request/78312/
�[36m⠹�[39m Querying API for job/node-test-pull-request/78312/
✔  Build data downloaded
�[36m⠹�[39m Checking whether PR CI job 78312 can be resumed
�[36m⠹�[39m Checking whether PR CI job 78312 can be resumed
✔  Jenkins offers a Resume build action
�[36m⠸�[39m Checking failures against changed PR files
�[36m⠸�[39m Checking failures against changed PR files
�[36m⠼�[39m Querying data for job/node-test-pull-request/78312/
�[36m⠼�[39m Querying API for job/node-test-pull-request/78312/
✔  Build data downloaded
�[36m⠼�[39m Querying failures of job/node-test-commit/93178/
�[36m⠼�[39m Querying failures of job/node-test-commit/93178/
�[36m⠼�[39m Querying API for job/node-test-commit-osx/74044/
�[36m⠼�[39m Querying API for job/node-test-commit-linux-containered/59803/
�[36m⠴�[39m Querying API for job/node-test-commit-osx/nodes=macos15-x64/74044/
�[36m⠴�[39m Querying console text for job/node-test-commit-osx/nodes=macos15-x64/74044/
�[36m⠦�[39m Querying API for job/node-test-commit-linux-containered/nodes=ubuntu2404_sharedlibs_withoutssl_x64/59803/
�[36m⠧�[39m Querying console text for job/node-test-commit-linux-containered/nodes=ubuntu2404_sharedlibs_withoutssl_x64/59803/
✔  Data downloaded
   ✖  test/parallel/test-child-process-spawn-timeout-kill-signal.js
   ℹ  https://ci.nodejs.org/job/node-test-commit-osx/nodes=macos15-x64/74044/consoleText
not ok 334 parallel/test-child-process-spawn-timeout-kill-signal
  ---
  duration_ms: 894.85200
  severity: fail
  exitcode: 1
  stack: |-
    node:internal/assert/utils:146
      throw error;
      ^
    
    AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
    
    null !== 0
    
        at ChildProcess.<anonymous> (/Users/admin/build/workspace/node-test-commit-osx/nodes/macos15-x64/test/parallel/test-child-process-spawn-timeout-kill-signal.js:41:12)
        at ChildProcess.<anonymous> (/Users/admin/build/workspace/node-test-commit-osx/nodes/macos15-x64/test/common/index.js:512:15)
        at ChildProcess.emit (node:events:514:20)
        at ChildProcess._handle.onexit (node:internal/child_process:324:12) {
      generatedMessage: true,
      code: 'ERR_ASSERTION',
      actual: null,
      expected: 0,
      operator: 'strictEqual',
      diff: 'simple'
    }
    
    Node.js v27.0.0-pre
  ...
✖  Refusing to resume CI: failures reference files changed by this PR

View workflow run

@inoway46

Copy link
Copy Markdown
Contributor

#66639 (comment)
It looks like the newly added test is failing.

The cases where the timeout expires after the child exited gave the
child 500 ms to start, spawn a descendant and exit, which a loaded
macOS worker did not meet, so the timer killed the child instead.

Let the child print the pid of the descendant and end it from the
test once the timer has fired, with a timeout of three seconds.

Signed-off-by: marcopiraccini <marco.piraccini@gmail.com>
The cases where the timeout expires after the child exited gave the
child 500 ms to start, spawn a descendant and exit, which a loaded
macOS worker did not meet, so the timer killed the child instead.

Let the child print the pid of the descendant and end it from the
test once the timer has fired, with a timeout of five seconds.

Signed-off-by: marcopiraccini <marco.piraccini@gmail.com>
@marcopiraccini

marcopiraccini commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor Author

#66639 (comment) It looks like the newly added test is failing.

Updated, can you trigger (jenkins) ci again? @ShogunPanda ?

@inoway46

Copy link
Copy Markdown
Contributor

I can’t trigger Jenkins CI myself. We need a new collaborator approval.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

child_process Issues and PRs related to the child_process subsystem. needs-ci PRs that need a full CI run. resume-ci-failed Resuming CI with the resume-ci label failed and requires manual intervention. semver-minor PRs that contain new features and should be released in the next minor version.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Know when a process ended due to the child_process.spawn() timeout option

4 participants